
// This file presupposes that GF.js has been loaded


function GRASPTree(grammar, tree, node) {
    this._grammar = grammar;
    this.setTree(tree, node);
};

GRASPTree.prototype = {
    getGrammar : function() {
        return this._grammar;
    },

    setTree : function(tree, node) {
        this._tree = tree;
        this.setNode(node);
    },

    getTree : function() {
        return this._tree;
    },

    setNode : function(node) {
        this._node = node;
    },

    getNode : function() {
        return this._node;
    },

    getLin : function() {
        if (! this._lin) 
            this._lin = this.getGrammar().linearise(this.getTree());
        return this._lin;
    },

    getWordAtIndex : function(index) {
        return this.getLin()[index].word;
    },

    getNodeAtIndex : function(index) {
        return this.getLin()[index].node;
    },

    getNodeIndices : function(node) {
        var lin = this.getLin();
        var result = [];
        for (var i=0; i < lin.length; i++) {
            if (startswith(lin[i].node, node))
                result.push(i);
        }
        return result;
    },

    selectNodeAtIndex : function(index) {
        this.setNode(this.getNodeAtIndex(index));
    },

    removeSelection : function() {
        this.setNode();
    },

    expandSelection : function() {
        var node = this.getNode();
        var selectedIndices = this.getNodeIndices(node);
        while (node) {
            node = node.slice(0, -1);
            var newIndices = this.getNodeIndices(node);
            if (newIndices.length > selectedIndices.length) {
                this.setNode(node);
                return newIndices;
            }
        }
    }
};


/** GRASPTree.editCommand(cmd, node, ?subtrees_or_node): perform an editing command
   @param cmd: a Function, currently one of 
               deletePhrase, similarPhrase, insertPhrase, replacePhrase
   @param node: a string of digits "0"-"9" representing a tree node
   @param subtrees_or_node: one of these:
          1. an Array of GFTree objects to add to the current tree
             (only necessary for cmd = insertPhrase or replacePhrase) 
	  2. a node (string of digits) representing the new position of the tree
 	     (only necessary for cmd = movePhrase)
   @return: an Array of GRASPTree's
**/

GRASPTree.prototype.editCommand = function(cmd, node, subtrees_or_node) {
    var grammar = this.getGrammar();
    var tree = this.getTree();
    if (node instanceof Array) node = node.join("");
    if (subtrees_or_node instanceof Array) {
        for (var i=0; i < subtrees_or_node.length; i++) {
            if (subtrees_or_node[i] instanceof GRASPTree)
                subtrees_or_node[i] = subtrees_or_node[i].getTree();
        }
    }
    if (cmd == deletePhrase) {
	var subresults = cmd(grammar, node, tree, subtrees_or_node);
	if (subresults && subresults.length) {
	    var results = [];
	    foreach(subresults, function(res) {
                results.push(new GRASPTree(grammar, res.tree, res.node));
	    });
	    return results;
        }
    } else if (cmd == movePhrase) {
        var newnode = subtrees_or_node;
	var deletedresults = deletePhrase(grammar, node, tree);
	if (deletedresults && deletedresults.length) {
	    var results = [];
	    foreach(deletedresults, function(res) {
                var grasptree = new GRASPTree(grammar, res.tree, res.node);
                var newresults = grasptree.editCommand(insertPhrase, newnode, [res.deleted]);
                foreach(newresults, function(newres) {
                    results.push(newres);
                });
	    });
	    return results;
        }
    } else {
        for (var i = node.length; i > 0; i--) {
	    var subnode = node.slice(0,i);
	    var subtree = tree.getSubtree(subnode);
	    if (subtree) {
	        var subresults = cmd(grammar, node.slice(i), subtree, subtrees_or_node);
	        if (subresults && subresults.length) {
		    var results = [];
		    foreach(subresults, function(res) {
		        var newnode = res.node == null ? null : subnode + res.node;
                        var newtree = tree.updateCopy(subnode, function(){return res.tree});
                        results.push(new GRASPTree(grammar, newtree, newnode));
		    });
		    return results;
	        }
            }
	}
    }
}


//////////////////////////////////////////////////////////////////////
// grammar specific editing operations
// DO NOT RELY ON THESE - they might change anytime and without warning

// function lookupTreeInDB(tree, db) {
//     var next = db[tree[0]];
// }

// deleteDB = {"AdjCN": function(path,tree){return startswith(path,[1]) && tree[2]},
// 	    "DetCN": {"den_det": {"AdjCN": function(path,tree){return startswith(path,[1]) && [tree[0], emptydet, tree[2]]}

// function deletePhrase(path, tree, treecat) {
//     var deltree = lookupPath(path, tree);
//     if (!isEmptyPhrase(deltree, tree, path)) {
// 	var simtrees = getSimilarTrees(deltree);
// 	for (var i in simtrees) {
// 	    var simtree = simtrees[i];
// 	    if (isEmptyPhrase(simtree, tree, path)) {
// 	    }
// 	}
//     }
// }


// function isEmptyPhrase(tree, context) {
//     return (tree[0] == "pl_indef")
// 	|| (tree[0] == "den_det" && context[0] == "UseN")
// 	|| (tree[0] == "de" && context[0] == "UseN");
// }

// den_det : Det;
// en_ett : Det;
// de : Det;
// pl_indef : Det;
// nagon_t : Det;
// nagra : Det;

function deleteTopLevel(grammar, lin, node, tree) {
    var results = [];
    for (var i = node.length-1; i > 0; i++) {
	var subTree = lookupNode(node.slice(0,i), tree);
	// replace child k: (XP d1 .. dk .. dn) -> dm, if dm==(XP ...)
	for (var j = 0; j < subTree.dtrs.length; j++) {
	    if (j != node[i] && subTree.type == subTree.dtrs[j].type) {
		var newTree = updateNode(node.slice(0,i), tree, subTree.dtrs[j]); ///
		results.push({node:null, tree:newTree});
	    }
	}
	// replace child k: (XP d1 .. dk .. dn) -> (XP d1 .. dk' .. dn), if dk' -> epsilon
	var toRemove = subTree.dtrs[node[i]];
	var similars = similarFunctions(toRemove.type);
	for (var j = 0; j < similars.length; j++) {
	    var newTree = updateNode(node, tree, similars[j]); ///
	    var newLin = grammar.linearise(newTree); ///
	    if (newLin.every(function(p){return nodeStartsWith(p.slice(1), node.slice(0,i+1))})) { ///
		results.push({node:null, tree:newTree});
	    }
	}
	if (results.length > 0)
	    return results;
    }
}

function deletePhrase(grammar, node, tree) {
    var results = [];
    // var lin = grammar.linearise(tree);
    if (node instanceof Array)
	node = node.join("");
    for (var i = node.length; i > 0; i--) {
	var subnode = node.slice(0,i);
	var subtree = tree.getSubtree(subnode);
	if (subtree) {
	    var delnode = node.slice(i);
	    if (startswith(delnode, "0") && subtree.node == "AdjCN") {
		results.push({node: null, 
			      tree: tree.updateCopy(subnode, function(old){return subtree.dtrs[1]}),
			      deleted: subtree.dtrs[0]});
	    }
	    if (startswith(delnode, "0") && subtree.node == "DetCN") {
    		if (!isEmptyPhrase(subtree.dtrs[0], subtree.dtrs[1])) {
		    var simphrases = getSimilarPhrases(subtree.dtrs[0]);
    		    for (var i in simphrases) {
			emptydet = simphrases[i];
    			if (isEmptyPhrase(emptydet, subtree.dtrs[1])) {
    			    results.push({node: null, 
					  tree: tree.updateCopy(subnode, function(old){
					      return T(subtree.node, subtree.type, [emptydet, subtree.dtrs[1]])
					  }), 
					  deleted: subtree.dtrs[0]});
    			}
    		    }
    		}
	    }
	    if (results.length)
		return results;
	}
    }
}

function insertPhrase(grammar, node, tree, instrees) {
    var results = [];
    for (var i = 0; i < instrees.length; i++) {
	var instree = instrees[i];
	if (instree.type == "Det" && tree.node == "DetCN") {
	    if (isEmptyPhrase(tree.dtrs[0], tree.dtrs[1])) {
		var simphrases = getSimilarPhrases(tree.dtrs[0]);
		for (var i in simphrases) {
		    if (instree.equals(simphrases[i])) {
			results.push({node:"0", tree:T(tree.node, tree.type, [instree, tree.dtrs[1]])});
		    }
		}
	    }
	} 
	if (instree.type == "AP" && (tree.node == "UseN" || tree.node == "AdjCN")) {
	    results.push({node:"0", tree:T("AdjCN", tree.type, [instree, tree])});
	}
    }
    return results;
}

function movePhrase(grammar, node, tree, newnode) {
    var results = [];
    var deletedresults = command(grammar, deletePhrase, node, tree);
    foreach(deletedresults, function(delresult) {
	var newresults = command(grammar, insertPhrase, newnode, delresult.tree, [delresult.deleted]);
	foreach(newresults, function(newres) {
	    results.push(newres);
	});
    });
    return results;
}

function replacePhrase(grammar, node, tree, repltrees) {
    var results = [];
    foreach(repltrees, function(repltree) {
	if (tree.type == repltree.type) 
	    results.push({node:"", tree:repltree});
    });
    return results;
}

function similarPhrase(grammar, node, tree) {
    var results = [];
    if (tree.type == "N" || tree.type == "A" || tree.type == "Prep" || tree.type == "Conj") {
	var simphrases = getSimilarPhrases(tree);
	foreach(simphrases, function(sim) {
	    results.push({node:"", tree:sim});
	});
    }
    if (startswith(node[0], "0") && tree.node == "DetCN") {
	if (!isEmptyPhrase(tree.dtrs[0], tree.dtrs[1])) {
	    var simphrases = getSimilarPhrases(tree.dtrs[0]);
	    foreach(simphrases, function(det) {
		if (!isEmptyPhrase(det, tree.dtrs[1])) 
		    results.push({node:"0", tree:T(tree.node, tree.type, [det, tree.dtrs[1]])});
	    });
	}
    }
    if (startswith(node, "01") && tree.type == "Cl") {
	var simphrases = getSimilarPhrases(tree);
	foreach(simphrases, function(sim) {
	    results.push({node:"01", tree:sim});
	});
    }
    return results;
}

//////////////////////////////////////////////////////////////////////
// Similar trees

/*
  similarTree(grammar, gftree, node, insert)
  - insert: null | a GF tree to insert
  --> [{'startnode': node, 'endnode': node|null, 'tree': new gftree}, ...]
*/

function similarTree(grammar, node, tree, insert) {
    for (var i = node.length; i > 0; i--) {
	var subnode = node.slice(0,i);
	var subtree = tree.getSubtree(subnode);
	if (subtree) {
            var simlist = SIMILARS[subtree.type];
            if (simlist) {
                console.log("# " + subnode + "  #  " + subtree);
                var results = [];
                simlist.forEach(function(sims){
                    console.log("| ", sims.join(" | ")); //  sim[0] + "  |  " + sim[1]);
                    var matches = matchTrees(sims, subtree);
                    matches.forEach(function(match){
                        console.log(": " + match.toString(match.unknown_node) + "  :  " + insert);
                        if (Boolean(insert) == Boolean(match.unknown_node)) {
                            if (match.unknown_node) {
                                console.log("-", match.unknown_node, insert);
                                match.updateSubtree(match.unknown_node, insert);
                            } 
                            console.log("+", subnode, match);
                            var simTree = tree.updateCopy(subnode, match);
                            console.log("-> " + simTree);
                            var startnode = endnode = "";
                            results.push({'startnode': subnode + startnode, 
                                          'endnode': subnode + endnode, 
                                          'tree': simTree});
                        }
                    });
                });
                if (results.length) 
                    return results;
            }
        }
    }
}

function matchTrees(sims, tree) {
    var results = [];
    for (var i=0; i<sims.length; i++) {
        var matches = [];
        if (treeCompare(sims[i], tree, matches)) {
            console.log("?", i, sims[i]+"", tree+"", matches);
            for (var j=0; j<sims.length; j++) {
                if (i != j) {
                    var newTree = buildTree(sims[j], matches);
                    var unknown = newTree.find(function(t){return t == null});
                    if (unknown)
                        newTree.unknown_node = unknown;
                    console.log("&", i, j, newTree+"");
                    results.push(newTree);
                }
            }
        }
    }
    return results;
}

function buildTree(template, matches) {
    if (template == null) {
        return null;
    } else if (typeof(template) == "number") {
        return matches[template];
    } else {
        var dtrs = template.dtrs.map(function(dtr){
            return buildTree(dtr, matches);
        });
        return T(template.node, template.type, dtrs);
    }
}

function treeCompare(pattern, tree, matches) {
    if (typeof(pattern) == "number") {
        matches[pattern] = tree;
        return true;
    } else if (pattern instanceof GFTree && tree instanceof GFTree &&
               pattern.type == tree.type && 
               pattern.node == tree.node &&
               pattern.dtrs.length == tree.dtrs.length) {
        for (var i=0; i<pattern.dtrs.length; i++) {
            if (! treeCompare(pattern.dtrs[i], tree.dtrs[i], matches))
                return false;
        }
        return true;
    } else {
        return false;
    }
}

// def getSimilars(typ) {
//     var sims = SIMILARS[typ];
//     for 
// }

function FOCUS(t) { return t; }

SIMILARS = {}

SIMILARS['CN'] = [
    // ["1", "(AdjCN:CN *? 1)"],
    [1, T("AdjCN", "CN", [FOCUS(null), 1])],
]

SIMILARS['Det'] = [
    // ["*(en_ett:Det)", "*(den_det:Det)", "*(pl_indef:Det)"],
    [FOCUS(T("en_ett", "Det")), FOCUS(T("den_det", "Det")), FOCUS(T("pl_indef", "Det"))],
    // ["*(nagra:Det)", "*(pl_indef:Det)", "*(en_ett:Det)"],
    [T("nagra", "Det"), T("pl_indef", "Det"), T("en_ett", "Det")],
    // ["*(pl_indef:Det)", "*(nagra:Det)", "*(en_ett:Det)", "*(de:Det)"],
    [T("pl_indef", "Det"), T("nagra", "Det"), T("en_ett", "Det"), T("de", "Det")],
    // ["*(den_det:Det)", "*(en_ett:Det)", "*(de:Det)"],
    [T("den_det", "Det"), T("en_ett", "Det"), T("de", "Det")],
]

SIMILARS['A'] = [
    // ["*(lustig:A)", "*(liten:A)", "*(stark:A)"],
    [T("lustig", "A"), T("liten", "A"), T("stark", "A")],
]


// FocusedTree
//     .hasParent() => bool
//     .hasChild(nr) => bool
//     .nrChildren() => int
//     .moveUp() => bool
//     .moveDown(childnr) => bool
//     .moveLeft() => bool
//     .moveRight() => bool
//     .getFocus() => node
//     .setFocus(node)
//     .getSubtree(?node) => FocusedTree (?)
//     .updateSubtree(newsub, ?node)


//////////////////////////////////////////////////////////////////////
// Grammar specific functions
// (should be auto-generated from GF)

function isEmptyPhrase(tree, context) {
    return (tree.node == "pl_indef")
	|| (tree.node == "den_det" && context.node == "UseN")
	|| (tree.node == "de" && context.node == "UseN");
}

function getSimilarPhrases(tree) {
    var lookup = similarFunctions[tree.type] || {};
    var funs = lookup[tree.node] || [];
    return funs.map(function(f){
	return T(f, tree.type, tree.dtrs)
    });
}

similarFunctions = {}

similarFunctions["Det"] = {"en_ett": ["den_det","pl_indef"],
			   "nagra": ["pl_indef","en_ett"],
			   "pl_indef": ["nagra","en_ett","de"],
			   "den_det": ["en_ett","de"]
			    };

similarFunctions["Prep"] = {"pa": ["i","med"],
			    "i": ["pa"],
			    "med": ["pa"]
			   };

similarFunctions["A"] = {"lustig": ["liten","stark"],
			 "liten": ["lustig","stark"],
			 "stark": ["liten","lustig"]
			};

similarFunctions["N"] = {"kulle": ["hus","burk"],
			 "bjorn": ["van","burk"],
			 "hus": ["kulle"],
			 "burk": ["kulle","bjorn"],
			 "van": ["bjorn"]
			};

similarFunctions["Cl"] = {"Gor": ["Gjorde","HarGjort","GorInte"],
			  "Gjorde": ["Gor","HarGjort","GjordeInte"],
			  "HarGjort": ["Gor","Gjorde","HarInteGjort"],
			  "GorInte": ["Gor"],
			  "GjordeInte": ["GjordeInte"]
			 };

similarFunctions["V"] = {"ligger": ["tittar","bor"],
			 "tittar": ["ligger"]
			};

similarFunctions["Conj"] = {"och": ["komma_och","men"],
			    "men": ["komma_men","och"],
			    "komma_och": ["och","komma_men"],
			    "komma_men": ["men","komma_och"]
			   };

//////////////////////////////////////////////////////////////////////
// Example trees

var examples = {};

examples["short"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V_Adv", "Cl",
			[T("DetCN", "NP", 
			   [T("en_ett", "Det"), 
			    T("AdjCN", "CN", 
			      [T("PositA", "AP", [T("lustig", "A")]), 
			       T("AdjCN", "CN", 
				 [T("PositA", "AP", [T("liten", "A")]), 
				  T("UseN", "CN", [T("hus", "N")])])])]),
			 T("ligger", "V_Adv"),
			 T("PrepNP", "Adv",
			   [T("pa", "Prep"), 
			    T("DetCN", "NP",
			      [T("nagra", "Det"), 
			       T("UseN", "CN", [T("kulle", "N")])])])])])]);

examples["short-0"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V_Adv", "Cl",
			[T("DetCN", "NP", 
			   [T("en_ett", "Det"), 
			    T("AdjCN", "CN", 
			      [T("PositA", "AP", [T("liten", "A")]), 
			       T("UseN", "CN", [T("hus", "N")])])]),
			 T("ligger", "V_Adv"),
			 T("PrepNP", "Adv",
			   [T("pa", "Prep"), 
			    T("DetCN", "NP",
			      [T("nagra", "Det"), 
			       T("UseN", "CN", [T("kulle", "N")])])])])])]);

examples["short-1"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V_Adv", "Cl",
		     [T("DetCN", "NP", 
			[T("en_ett", "Det"), 
			 T("UseN", "CN", [T("hus", "N")])]),
		      T("ligger", "V_Adv"),
		      T("PrepNP", "Adv", 
			[T("pa", "Prep"), 
			 T("DetCN", "NP", 
			   [T("den_det", "Det"), 
			    T("UseN", "CN", [T("kulle", "N")])])])])])]);

examples["short-2"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V", "Cl",
		     [T("DetCN", "NP", 
			[T("en_ett", "Det"), 
			 T("UseN", "CN", [T("hus", "N")])]),
		      T("ligger_still", "V")])])]);

examples["short-3"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V", "Cl",
		     [T("DetCN", "NP", 
			[T("en_ett", "Det"), 
			 T("AdjCN", "CN", 
			   [T("PositA", "AP", [T("liten", "A")]), 
			    T("UseN", "CN", [T("hus", "N")])])]),
		      T("ligger_still", "V")])])]);

examples["short-4"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V", "Cl",
		     [T("DetCN", "NP", 
			[T("pl_indef", "Det"), 
			 T("UseN", "CN", [T("hus", "N")])]),
		      T("ligger_still", "V")])])]);

examples["short-5"] =
    T("Pastaende", "Text",
      [T("Gor", "S", [T("FrontSubj_Subj_V", "Cl",
		     [T("DetCN", "NP", 
			[T("pl_indef", "Det"), 
			 T("AdjCN", "CN", 
			   [T("PositA", "AP", [T("liten", "A")]), 
			    T("UseN", "CN", [T("hus", "N")])])]),
		      T("ligger_still", "V")])])]);

examples["long-1"] = 
    T("Pastaende", "Text",
      [T("Gor", "S", 
      [T("FrontAdv_Subj_V_Adv", "Cl", 
	 [T("DetCN", "NP", 
	    [T("nagra", "Det"), 
	     T("AdjCN", "CN", 
	       [T("PositA", "AP", [T("lustig", "A")]),
		T("UseN", "CN", [T("hus", "N")])])]),
	  T("ligger", "V_Adv"),
	  T("PrepNP", "Adv", 
	    [T("pa", "Prep"), 
	     T("DetCN", "NP", 
	       [T("pl_indef", "Det"), 
		T("AdvCN", "CN", 
		  [T("AdjCN", "CN", 
		     [T("PositA", "AP", [T("liten", "A")]),
		      T("UseN", "CN", [T("kulle", "N")])]), 
		   T("PrepNP", "Adv",
		     [T("i", "Prep"), 
		      T("DetCN", "NP", 
			[T("den_det", "Det"), 
			 T("UseN", "CN", [T("sol", "N")])])])])])])])])]);

// examples["long-2"] =
//     ["Gor", "X", [T("FrontAdv_Subj_V_Adv",
// 	     ["ConjNP", "X", [T("och"],
// 	      ["UsePN", "X", [T("bamse"]],
// 	      ["DetCN", "X", [T("GenPl", "X", [T("UsePron", "X", [T("han"]]], ["UseN", "X", [T("van"]]]],
// 	     ["bor"],
// 	     ["dar"]]];

// examples["long-3"] = 
//     ["ConjS", "X", [T("komma_men"],
//      ["Gor", "X", [T("PredVP",
// 	      ["UsePN", "X", [T("bamse"]],
// 	      ["AdvVP",
// 	       ["AdVVP", "X", [T("alltid"], 
// 		["ComplV_NP", "X", [T("borjar"],
// 		 ["DetCN", "X", [T("den_det", "X"), T("UseN", "X", [T("dag"]]]]],
// 	       ["PrepNP", "X", [T("med"], 
// 		["DetCN", "X", [T("en_ett"],
// 		 ["ApposCN", "X", [T("UseN", "X", [T("burk"]], ["MassNP", "X", [T("UseN", "X", [T("honung"]]]]]]]]],
//      ["GorInte", "X", [T("PredVP",
// 		  ["UsePron", "X", [T("det"]],
// 		  ["UseComp", "X", [T("CompNP", "X", [T("som_helst", "X", [T("IdetCN", "X", [T("vilken_t"], 
// 							["UseN", "X", [T("honung"]]]]]]]]];

// examples["long-4"] = 
//     ["ConjS", "X", [T("komma_och"],
//      ["Gor", "X", [T("PredVP", "X", [T("UsePron", "X", [T("det"]],
// 	      ["ComplV_Comp", "X", [T("ar"], 
// 	       ["CompNP", "X", [T("DetCN", "X", [T("GenSg", "X", [T("UsePN", "X", [T("farmor"]]],
// 			   ["UseN", "X", [T("dunderhonung"]]]]]]],
//      ["AdvS", "X", [T("SubjS", "X", [T("nar"],
// 	       ["HarGjort", "X", [T("PredVP", "X", [T("UsePron", "X", [T("han"]],
// 			     ["AdvVP", "X", [T("UseV", "X", [T("ater"]], 
// 			      ["PrepNP", "X", [T("av", "X"), T("UsePron", "X", [T("den"]]]]]]],
//       ["Gor", "X", [T("PredVP", "X", [T("UsePron", "X", [T("han"]],
// 	       ["ComplV_Comp", "X", [T("blir"],
// 		["CompNP", "X", [T("DetCN",
// 			    ["GenSg", "X", [T("DetCN", "X", [T("den_det", "X"), T("UseN", "X", [T("varld"]]]],
// 			    ["AdjCN", "X", [T("SuperlA", "X", [T("stark"]], ["UseN", "X", [T("bjorn"]]]]]]]]]];

//////////////////////////////////////////////////////////////////////
// Example lexicon

lexicon = {};

lexicon["adjektiv"] = {
    "stark": [T("PositA", "AP", [T("stark", "A")])],
    "lustig": [T("PositA", "AP", [T("lustig", "A")])],
    "liten": [T("PositA", "AP", [T("liten", "A")])]
};
lexicon["substantiv"] = {
    "kulle": [T("UseN", "CN", [T("kulle", "N")])],
    "hus": [T("UseN", "CN", [T("hus", "N")])],
    "sol": [T("UseN", "CN", [T("sol", "N")])],
    "honung": [T("UseN", "CN", [T("honung", "N")])],
    "vän": [T("UseN", "CN", [T("van", "N")])],
    "burk": [T("UseN", "CN", [T("burk", "N")])],
    "dag": [T("UseN", "CN", [T("dag", "N")])],
    "dunderhonung": [T("UseN", "CN", [T("dunderhonung", "N")])],
    "värld": [T("UseN", "CN", [T("varld", "N")])],
    "björn": [T("UseN", "CN", [T("bjorn", "N")])]
};
lexicon["namn"] = {
    "Bamse": [T("UsePN", "NP", [T("bamse")])],
    "Skalman": [T("UsePN", "NP", [T("skalman")])],
    "Lille Skutt": [T("UsePN", "NP", [T("lille_skutt")])],
    "Farmor": [T("UsePN", "NP", [T("farmor")])]
};
lexicon["prepositioner"] = {
    "på": [T("pa", "Prep")],
    "i": [T("i", "Prep")],
    "med": [T("med", "Prep")],
    "av": [T("av", "Prep")]
};
lexicon["adverb"] = {
    "där": [T("dar", "Adv")],
    "alltid": [T("alltid", "Adv")],
    "aldrig": [T("aldrig", "Adv")],
    "inte": [T("inte", "Adv")]
};
lexicon["verb"] = {
    "ligger": [T("ligger", "V_Adv")],
    "bor": [T("bor", "V_Adv")],
    "tittar": [T("tittar", "V_Adv")],
    "börjar": [T("borjar", "V_NP")],
    "blir": [T("blir", "V_Comp")],
    "äter": [T("ater", "V")],
    "är": [T("ar", "V_Comp")]
};
lexicon["determinerare/pronomen"] = {
    "några": [T("nagra", "Det")],
    "en": [T("en_ett", "Det")],
    "ett": [T("en_ett", "Det")],
    "den": [T("den_det", "Det"), 
	    T("UsePron", "NP", [T("den", "Pron")])],
    "det": [T("den_det", "Det"), 
	    T("UsePron", "NP", [T("det", "Pron")])],
    "de": [T("de", "Det")],
    "någon": [T("nagon_t", "Det")],
    "något": [T("nagon_t", "Det")]
};
lexicon["pronomen"] = {
    "han": [T("UsePron", "NP", [T("han", "Pron")])],
    "hon": [T("UsePron", "NP", [T("hon", "Pron")])],
    "jag": [T("UsePron", "NP", [T("jag", "Pron")])],
    "du": [T("UsePron", "NP", [T("du", "Pron")])],
    "dom": [T("UsePron", "NP", [T("dom", "Pron")])]
};
lexicon["frågepronomen"] = {
    "vilken": [T("vilken_t", "IDet")],
    "vilket": [T("vilken_t", "IDet")],
    "vilka": [T("vilka", "IDet")]
};
lexicon["relativpronomen"] = {
    "som": [T("som", "RP")]
};
lexicon["konjunktioner"] = {
    "och": [T("och", "Conj")],
    "men": [T("men", "Conj")],
    "när": [T("nar", "Conj")]
};
